use crate::app::core::{HttpRouterOpt, HttpRouterOptTy, OptResponse, RouterOps};
use crate::app::htp::{HttpControlRouter, HttpHandle};
use hyper::client::HttpConnector;
use hyper::Client;
use hyper::{Body, Request, Response, Uri};
use hyper_tls::HttpsConnector;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
use wd_run::Context;

pub struct HtpRouterMiddle {
    #[allow(dead_code)]
    client_hts: Client<HttpsConnector<HttpConnector>>,
    client_htp: Client<HttpConnector>,
    router: Arc<RouterMap>,
}

impl HtpRouterMiddle {
    pub fn new() -> (HtpRouterMiddle, HtpRouterControl) {
        let client_hts = Client::builder().build(HttpsConnector::new());
        let client_htp = Client::builder().build_http();
        let router = Arc::new(RouterMap::new());
        let ctl = HtpRouterControl {
            router: router.clone(),
        };
        let hrm = Self { client_hts,client_htp, router };
        (hrm, ctl)
    }
    async fn find_router(
        &self,
        host: &str,
        path: &str,
    ) -> Result<Arc<HttpRouterOpt>, Response<Body>> {
        if let Some(r) = self.router.find(host, path).await {
            return Ok(r);
        }
        return Err(Response::builder()
            .status(404)
            .body(Body::from("not found"))
            .unwrap());
    }
}
#[async_trait::async_trait]
impl HttpHandle for HtpRouterMiddle {
    async fn request(
        &self,
        _ctx: Context,
        req: Request<Body>,
    ) -> Result<Request<Body>, Response<Body>> {
        let host = super::util::get_host(&req);
        let s = self.find_router(&host, req.uri().path()).await?;
        // println!("request schema:{}", req.uri());
        let host = if s.target_port == 80 {
            format!("{}.{}", &s.target_host, &s.namespaces)
        } else {
            format!("{}.{}:{}", &s.target_host, &s.namespaces, &s.target_port)
        };
        let uri = Uri::builder()
            // .authority(option.unwrap().clone())
            .authority(host)
            .path_and_query(req.uri().path_and_query().unwrap().clone())
            // .scheme(match req.uri().scheme() {
            //     Some(s) => s.clone(),
            //     None => "http".parse().unwrap(),
            // })
            .scheme("http")
            .build()
            .unwrap();
        let mut request = Request::builder().version(req.version()).uri(uri);
        for (k, v) in req.headers().iter() {
            request = request.header(k.clone(), v.clone());
        }
        let request = request.body(req.into_body()).unwrap();
        // let res = if let Some(s) = req.uri().scheme() {
        //     match s.as_str() {
        //         "https"=>self.client_hts.request(request).await,
        //         _=>self.client_htp.request(request).await,
        //     }
        // }else{self.client_htp.request(request).await };
         let res = self.client_htp.request(request).await;
        if let Err(err) = res {
            return Err(Response::builder()
                .status(500)
                .body(Body::from(format!("{}", err.to_string())))
                .unwrap());
        }
        Err(res.unwrap())
        // Err(Response::new(Body::from("hello world")))
    }

    // async fn response(&self, _ctx: Context, resp: Response<Body>) -> Response<Body> {
    //     todo!()
    // }
}

pub struct HtpRouterControl {
    router: Arc<RouterMap>,
}
#[async_trait::async_trait]
impl HttpControlRouter for HtpRouterControl {
    async fn router(
        &mut self,
        _ctx: Context,
        ops: RouterOps,
    ) -> anyhow::Result<Option<OptResponse>> {
        match ops {
            RouterOps::Http(rs) => {
                wd_log::log_info_ln!("开始http路由信息更新：{:?}", &rs);
                self.router.update(rs).await;
            }
            _ => {}
        }
        return Ok(None);
    }
}

#[cfg(test)]
mod test {
    use hyper::{Body, Uri};
    use hyper_tls::HttpsConnector;
    use std::sync::Arc;

    #[tokio::test]
    async fn htp_client() {
        let client = hyper::Client::builder().build::<_, Body>(HttpsConnector::new());
        let result = client.get(Uri::from_static("http://test.com:31666/hello")).await;
        match result {
            Ok(resp) => {
                let bytes = hyper::body::to_bytes(resp.into_body()).await.unwrap();
                let s = String::from_utf8(bytes.to_vec()).unwrap();
                println!("{}", s);
            }
            Err(e) => {
                println!("error:{}", e.to_string());
                panic!("草你妈的");
            }
        }
    }

    #[test]
    fn test_router() {
        let mut root = super::Router::new(String::from("/"), Some(String::from("www.baidu.com")));
        root.insert(
            super::Router::<String>::path_to_vec("/hello/world"),
            "www.cnblog.com".to_string(),
        );
        root.insert(
            super::Router::<String>::path_to_vec("/api/v1"),
            "www.csdn.com".to_string(),
        );
        root.insert(
            super::Router::<String>::path_to_vec("/api/v1"),
            "www.net.com".to_string(),
        );

        let res = root.find(super::Router::<String>::path_to_vec("/api"));
        assert_eq!(res, None, "获取 /api");
        let res = root.find(super::Router::<String>::path_to_vec("/hello/world"));
        assert_eq!(
            res.unwrap(),
            Arc::new(String::from("www.cnblog.com")),
            "获取 /hello/world"
        );
        let res = root.find(super::Router::<String>::path_to_vec("/api/v1/index"));
        assert_eq!(
            res.unwrap(),
            Arc::new(String::from("www.net.com")),
            "获取 /api/v1/index"
        );
        let res = root.find(super::Router::<String>::path_to_vec("/"));
        assert_eq!(
            res.unwrap(),
            Arc::new(String::from("www.baidu.com")),
            "获取 /"
        );
    }
}

struct RouterMap {
    index: AtomicUsize,
    routers: Vec<RwLock<HashMap<String, Router<HttpRouterOpt>>>>,
}
impl RouterMap {
    fn new() -> Self {
        let index = AtomicUsize::new(0);
        let map1 = RwLock::new(HashMap::new());
        let map2 = RwLock::new(HashMap::new());
        let routers = vec![map1, map2];
        Self { index, routers }
    }
    async fn update(&self, rs: Vec<HttpRouterOpt>) {
        let index = self.index.load(Ordering::Relaxed);
        let rt = self.routers[index].read().await;
        let mut map = rt.deref().clone();
        for i in rs.iter() {
            if let Some(hro) = map.get_mut(&i.host) {
                *hro = Router::new("/".to_string(), None);
            }
        }
        for i in rs.into_iter() {
            if i.opt_ty == HttpRouterOptTy::Delete {
                if map.get_mut(&i.host).is_some() {
                    map.remove(&i.host);
                }
                continue;
            }
            if let Some(hro) = map.get_mut(&i.host) {
                hro.insert(Router::<String>::path_to_vec(&i.path), i);
            } else {
                let mut router = Router::new("/".to_string(), None);
                let host = i.host.clone();
                router.insert(Router::<String>::path_to_vec(&i.path), i);
                map.insert(host, router);
            }
        }
        let index_next = if index == 1 { 0usize } else { 1 };
        let mut rt = self.routers[index_next].write().await;
        *rt.deref_mut() = map;
        self.index.store(index_next, Ordering::Relaxed);
    }
    async fn find(&self, host: &str, path: &str) -> Option<Arc<HttpRouterOpt>> {
        let index = self.index.load(Ordering::Relaxed);
        let router = self.routers[index].read().await;
        if let Some(r) = router.get(host) {
            let res = r.find(Router::<String>::path_to_vec(path));
            if res.is_some() {
                return res;
            }
        }
        for (host, router) in router.iter() {
            if host.len() >= 2 {
                let (prev, _) = host.split_at(2);
                if prev == "**" {
                    return router.find(Router::<String>::path_to_vec(path));
                }
            }
        }

        return None;
    }
}

#[derive(Clone)]
struct Router<T> {
    path: String,
    val: Option<Arc<T>>,
    children: Vec<Router<T>>,
}
impl<T> Router<T> {
    fn new(path: String, val: Option<T>) -> Self {
        let val = match val {
            Some(s) => Some(Arc::new(s)),
            None => None,
        };
        Self {
            path,
            val,
            children: vec![],
        }
    }
    fn path_to_vec<S: ToString>(s: S) -> Vec<String> {
        let s = s.to_string();
        let mut res = vec![];
        for i in s.split("/") {
            if !i.is_empty() {
                res.push(i.to_string());
            }
        }
        res
    }
}
impl<T> Router<T> {
    pub fn insert(&mut self, mut ss: Vec<String>, des: T) {
        if ss.len() == 0 {
            self.val = Some(Arc::new(des));
            return;
        }
        let s = ss.remove(0);
        for i in self.children.iter_mut() {
            if i.path == s {
                i.insert(ss, des);
                return;
            }
        }
        self.children.push(Router::new(s, None));
        self.children.last_mut().unwrap().insert(ss, des);
    }
    pub fn find(&self, mut ss: Vec<String>) -> Option<Arc<T>> {
        if ss.len() == 0 {
            return self.val.clone();
        }
        let s = ss.remove(0);
        for i in self.children.iter() {
            if i.path == s {
                return i.find(ss);
            }
        }
        self.val.clone()
    }
}
